home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / Classes / RCString / RCString.m < prev    next >
Text File  |  1995-06-12  |  7KB  |  332 lines

  1. #import <RCString.h>
  2. /*
  3.     Copyright (C) 1992. Bruce Ediger.
  4.  
  5.       This program is free software; you can redistribute it and/or modify
  6.     it under the terms of the GNU Library General Public License.
  7. */
  8.  
  9. @implementation RCString
  10.  
  11. // Initialize the internal string rep, but not the
  12. // internal string itself.
  13. // Assumes that "self" is already allocated.
  14. - init
  15. {
  16.     [super init];
  17.     if (p = (struct srep *) malloc(sizeof(struct srep))) {
  18.         p->s = NULL;
  19.         p->l = 0;
  20.         p->n = 1;
  21.     }
  22.     yCaseSensitive = YES;
  23.     return self;
  24. }
  25.  
  26. // construct an object with zero-length string internal string rep
  27. + new
  28. {
  29.     RCString *oNew = [[RCString alloc] init];
  30.     if (oNew) {
  31.         oNew->p->s = malloc(1);
  32.         *oNew->p->s = '\0';
  33.         oNew->p->l = 1;
  34.         oNew->p->n = 1;
  35.     }
  36.     return oNew;
  37. }
  38.  
  39. // Construct an object surrounding a given ASCII string.
  40. // Should this method make a copy of the ASCIIZ argument?
  41. // Since the object is copy-on-write, we could maybe get
  42. // away with just keeping around the pointer.  No.  Then
  43. // anything could change the string out from underneath the
  44. // object.
  45. + newFromString:(char *)aString
  46. {
  47.     RCString       *oNewString;
  48.     if (aString) {
  49.         oNewString = [[RCString alloc] init];
  50.         if (oNewString) {
  51.             oNewString->p->l = strlen(aString) + 1;
  52.             if ((oNewString->p->s = malloc(oNewString->p->l))) {
  53.                 bcopy(aString, oNewString->p->s, oNewString->p->l);
  54.                 oNewString->p->n = 1;
  55.             } else
  56.                 oNewString->p->l = 0;  // malloc() failed, retain consistency
  57.         }
  58.         oNewString->yCaseSensitive = YES;
  59.     } else {        // null argument string 
  60.         oNewString = [RCString new];
  61.     }
  62.  
  63.     return oNewString;
  64. }
  65.  
  66. // Factory Method copy constructor analog: an object that
  67. // references another object's internal string rep.
  68. + newFromObject:(RCString *) oString
  69. {
  70.     RCString       *oNewString;
  71.     if (oString && (oNewString = [RCString alloc])) {
  72.         // RCString objects will share internal string rep until a write.
  73.         oNewString->p = oString->p;
  74.         oNewString->p->n++;
  75.         oNewString->yCaseSensitive = oString->yCaseSensitive;
  76.     } else {
  77.          // passed a null object pointer: fill in a zero-length
  78.          // internal string rep
  79.         oNewString = [RCString new];
  80.     }
  81.     return oNewString;
  82. }
  83.  
  84. // Copy constructor analog: an object that references this
  85. // object's internal string rep.
  86. - newFromObject
  87. {
  88.     RCString       *oNewString;
  89.     if ((oNewString = [RCString alloc]))
  90.     {
  91.         // RCString objects will share internal string rep until a write.
  92.         oNewString->p = p;
  93.         oNewString->yCaseSensitive = yCaseSensitive;
  94.         if (p) p->n++;
  95.     }
  96.     return oNewString;
  97. }
  98.  
  99. + newFilledWith: (int) bCharacter size: (int) iNumber
  100. {
  101.     RCString       *oNewString;
  102.     char           *bpTmp;
  103.  
  104.     if (bCharacter && iNumber > 0 && (bpTmp = malloc(iNumber + 1))) {
  105.         int icCount;
  106.         for (icCount = 0; icCount < iNumber + 1; ++icCount)
  107.             bpTmp[icCount] = (char )bCharacter;
  108.         bpTmp[iNumber] = '\0';
  109.         oNewString = [RCString newFromString:bpTmp];
  110.     } else {
  111.         // args specifiy null/zero-length string or malloc() failure
  112.         oNewString = [RCString new];
  113.     }
  114.  
  115.     return oNewString;
  116. }
  117.  
  118. - free
  119. {
  120.     // should the test be "==" or "<=" ? 
  121.     // <= would probably catch some mistakes.
  122.     if (p && --p->n == 0) {
  123.         // reference count's gone to zero, free internal string rep 
  124.         if (p->s)
  125.             free(p->s);
  126.         free(p);
  127.     }
  128.     return [super free];
  129. }
  130.  
  131. // private use method. 
  132. // causes the RCString object that this message is sent to,
  133. // to copy it's internal string representation. 
  134. // typically called before modifying internal string rep 
  135. // in order to provide copy-on-write behavior. 
  136. - copyReference
  137. {
  138.     struct srep *psNewSrep = (struct srep *)malloc(sizeof(struct srep));
  139.     if (psNewSrep) {
  140.         if (p) {
  141.             if (p->s) {
  142.                 psNewSrep->s = malloc(p->l);
  143.                 if (psNewSrep->s) {
  144.                     bcopy(p->s, psNewSrep->s, p->l);
  145.                     psNewSrep->l = p->l;
  146.                 }
  147.             } else  {
  148.                 psNewSrep->s = NULL;
  149.                 psNewSrep->l = 0;
  150.             }
  151.             // check reference count on previous internal rep
  152.             if (--p->n == 0) {
  153.                 free(p->s);
  154.                 free(p);
  155.             }
  156.             psNewSrep->n = 1;
  157.             p = psNewSrep;
  158.         } else {
  159.             // Object didn't have an internal string rep for some
  160.             // reason. Give it it's own NULL string 
  161.             psNewSrep->s = NULL;
  162.             psNewSrep->n = 1;
  163.             psNewSrep->l = 0;
  164.             p = psNewSrep;
  165.         }
  166.     }  // what if malloc() of struct srep fails?
  167.     return self;
  168. }
  169.  
  170. - (BOOL) isNull
  171. {
  172.     if (!p && (!p->s || p->l <= 1))    // ignore trailing ASCII NULL
  173.         return YES;
  174.     return NO;
  175. }
  176.  
  177. // returns "strlen" of internal representation.
  178. // that is, length without trailing NULL.
  179. - (unsigned)length
  180. {
  181.     if (p && p->l)
  182.         return(p->l - 1);
  183.     return 0;
  184. }
  185.  
  186. - (char *)data
  187. {
  188.     return p ? p->s : NULL;
  189. }
  190.  
  191. - (int)references
  192. {
  193.     return p ? p->n : 0;
  194. }
  195.  
  196.  
  197. - (struct srep *)internal
  198. {
  199.     return p;
  200. }
  201.  
  202. @end
  203.  
  204. @implementation RCString(Archiving)
  205.  
  206. // Archiving methods borrowed from John Hassey's String
  207. // object.  Try to maintain compatibility.
  208. - storeOn: (int) aFd
  209. {
  210. #ifndef NeXT
  211.   [super storeOn: aFd];
  212. #endif
  213.  
  214.   if (write(aFd, &p->l, sizeof(p->l)) == -1)
  215.     {
  216.     [self error: "storeOn: write error"];
  217.     }
  218.   if (write(aFd, "\"", 1) == -1)
  219.     {
  220.     [self error: "storeOn: write error"];
  221.     }
  222.   if (write(aFd, [self data], [self length]) == -1)
  223.     {
  224.     [self error: "storeOn: write error"];
  225.     }
  226.   if (write(aFd, "\"", 1) == -1)
  227.     {
  228.     [self error: "storeOn: write error"];
  229.     }
  230.   return self;
  231. }
  232.  
  233. - readFrom: (int) aFd
  234. {
  235.   char c;
  236.  
  237. #ifndef NeXT
  238.   [super readFrom: aFd];
  239. #endif
  240.  
  241.   if (p == NULL) {
  242.     p = (struct srep *)malloc(sizeof(struct srep));
  243.   } else {
  244.     if (p->n == 1)
  245.         if (p->s) free(p->s);
  246.     else {
  247.         // Come up with a new internal rep struct.  It
  248.         // will be completely redone anyway.
  249.         --p->n;
  250.         p = (struct srep *)malloc(sizeof(struct srep));
  251.     }
  252.   }
  253.  
  254.   if (read(aFd, &p->l, sizeof(p->l)) == -1)
  255.     [self error: "readFrom: read error"];
  256.   p->s = malloc(p->l);
  257.   if (read(aFd, &c, 1) == -1)
  258.       [self error: "readFrom: read error"];
  259.   if (c != '"')
  260.     [self error: "readFrom: format error"];
  261.   if (read(aFd, p->s, p->l - 1) == -1)
  262.     [self error: "readFrom: read error"];
  263.   if (read(aFd, &c, 1) == -1)
  264.       [self error: "readFrom: read error"];
  265.   if (c != '"')
  266.     [self error: "readFrom: format error"];
  267.  
  268.   // null terminate string
  269.  
  270.   p->s[p->l - 1] = 0;
  271.  
  272.   return self;
  273. }
  274.  
  275. #ifdef NeXT
  276. - write:(NXTypedStream *)aStream
  277. {
  278.     [super write:aStream];
  279.     if (p)
  280.     {
  281.         int iFakeN = 1;
  282.         NXWriteType(aStream, "i", &p->l);  // length first, so read: can
  283.                                             // allocate memory for string.
  284.         if (p->s)
  285.             NXWriteType(aStream, "*", &p->s);
  286.         else {
  287.             char *bpTmp = "";
  288.             NXWriteType(aStream, "*", &bpTmp);
  289.         }
  290.         NXWriteType(aStream, "i", &iFakeN);
  291.         NXWriteType(aStream, "c", &yCaseSensitive);
  292.     } else {
  293.         // Fake the whole internal rep as a zero-length string.
  294.         char *bpTmp = "";
  295.         int   iTmpL = 1;
  296.         int   iTmpN = 1;
  297.         BOOL  yTmpCS = TRUE;
  298.         NXWriteType(aStream, "i", &iTmpL);
  299.         NXWriteType(aStream, "*", &bpTmp);
  300.         NXWriteType(aStream, "i", &iTmpN);
  301.         NXWriteType(aStream, "c", &yTmpCS);
  302.     }
  303.     
  304.     return self;
  305. }
  306.  
  307. - read:(NXTypedStream *)aStream
  308. {
  309.     [super read:aStream];
  310.  
  311.     // prepare internal string rep
  312.     if (p) {
  313.         if (p->n == 1) {
  314.             if (p->s) free(p->s);
  315.         } else {
  316.             --p->n;
  317.             p = (struct srep *)malloc(sizeof(struct srep));
  318.         }
  319.     } else {
  320.         p = (struct srep *)malloc(sizeof(struct srep));
  321.     }
  322.     NXReadType(aStream, "i", (void *)&p->l);
  323.     NXReadType(aStream, "*", (void *)&p->s);
  324.     NXReadType(aStream, "i", (void *)&p->n);
  325.     if (p->n != 1) [self error:"read: problem, ref count not 1"];
  326.     NXReadType(aStream, "c", (void *)&yCaseSensitive);
  327.     return self;
  328. }
  329. #endif
  330. @end
  331.  
  332.